#pragma once
#include <iostream>
#include <vector>
#include "Sem.hpp"
#include "Mutex.hpp"

static int gcap = 5;

template <class T>
class RingQueue
{
public:
    RingQueue(int cap = gcap)
        : _cap(cap), _ring_queue(cap), _space_sem(cap),
          _data_sem(0), _p_step(0), _c_step(0)
    {
    }

    // 入队列
    void Enqueue(const T &in)
    {
        // 先申请信号量，有信号量才可以生产
        _space_sem.P();
        {
            LockGuard lockguard(&_p_lock);
            // 生产数据了！
            _ring_queue[_p_step++] = in;
            // 维持环形特点
            _p_step %= _cap;
        }
        _data_sem.V();
    }
    // 出队列
    void Pop(T *out)
    {
        // 先申请信号量，有信号量才可以消费
        _data_sem.P();
        {
            LockGuard lockguard(&_c_lock);
            *out = _ring_queue[_c_step++];
            _c_step %= _cap;
        }
        _space_sem.V();
    }
    ~RingQueue()
    {
    }

private:
    std::vector<T> _ring_queue; // 临界资源
    int _cap;                   // 环形队列容量

    // 创建信号量
    Sem _space_sem;
    Sem _data_sem;

    // 生产和消费的位置
    int _p_step;
    int _c_step;

    // 两把锁，确保多线程访问临界资源时先申请对应锁
    Mutex _p_lock;
    Mutex _c_lock;
};